#include <iostream>
#include <pthread.h>
#include <unistd.h>
#include <vector>
#include <functional>
#include "blockqueue.hpp"
using namespace BlockQueueModule;

#if 0
// V3
typedef std::function<void()> fun_t;
template<typename T>
class Task
{
public:
    Task(std::vector<T> &task, BlockQueue<T> *bq)
        : _task(task), _bq(bq), _index(0)
    {
    }

    int GetIndex()
    {
        ++_index;
        _index %= _task.size();
        return _index;
    }

    ~Task() {}

    std::vector<T> _task;
    BlockQueue<T> *_bq;
    int _index;
};

void* Produce(void *args)
{
    Task<fun_t>* tk = static_cast<Task<fun_t> *>(args);
    /* 生产任务 */
    while(true)
    {
        sleep(1); // 模拟生产耗时
        tk->_bq->Enqueue(tk->_task[tk->GetIndex()]);
        std::cout << "生产一个任务... : " << std::endl;
    }
}

void* Consumer(void *args)
{
    Task<fun_t>* tk = static_cast<Task<fun_t> *>(args);
    while(true)
    {
        sleep(1);
        /* 消费任务 */
        fun_t action;
        tk->_bq->Pop(&action);
        std::cout << "消费一个任务... : " << std::endl;
        action();
    }
}

int main()
{
    fun_t fun1 = []()
    { std::cout << "下载任务..." << std::endl; };
    fun_t fun2 = []()
    { std::cout << "日志查看..." << std::endl; };
    fun_t fun3 = []()
    { std::cout << "上传任务..." << std::endl; };
    std::vector<fun_t> task = {fun1, fun2, fun3};

    /* 申请一个阻塞队列 */
    BlockQueue<fun_t> *bq = new BlockQueue<fun_t>();
    Task<fun_t>* tk = new Task<fun_t>(task, bq);

    std::vector<pthread_t> p(3);
    std::vector<pthread_t> c(5);
    /* create */
    for(int i = 0; i < p.size(); ++i)
    {
        pthread_create(&p[i], nullptr, Produce, (void*)tk);
    }

    for(int j = 0; j < c.size(); ++j)
    {
        pthread_create(&c[j], nullptr, Consumer, (void*)tk);
    }

    /* join */
    for(int i = 0; i < p.size(); ++i)
    {
        pthread_join(p[i], nullptr);
    }

    for(int j = 0; j < c.size(); ++j)
    {
        pthread_join(c[j], nullptr);
    }

    return 0;
}
#endif

#if 0
// v2
int cnt = 1;
void* Produce(void *args)
{
    BlockQueue<int> *bq = static_cast<BlockQueue<int> *>(args);
    /* 生产任务 */
    while(true)
    {
        // sleep(1); // 模拟生产耗时
        bq->Enqueue(cnt++);
        std::cout << "生产一个任务... : " << cnt << std::endl;
    }
}

void* Consumer(void *args)
{
    BlockQueue<int> *bq = static_cast<BlockQueue<int> *>(args);
    while(true)
    {
        sleep(1);
        /* 消费任务 */
        int data;
        bq->Pop(&data);
        std::cout << "消费一个任务... : " << data << std::endl;
    }
}

int main()
{
    /* 申请一个阻塞队列 */
    BlockQueue<int> *bq = new BlockQueue<int>();

    /* 单单 */
    // pthread_t p[1], c[1];
    // pthread_create(&p[0], nullptr, Produce, (void*)bq);
    // pthread_create(&c[0], nullptr, Consumer, (void*)bq);

    // pthread_join(p[0], nullptr);
    // pthread_join(c[0], nullptr);

    /* 多多 */
    std::vector<pthread_t> p(5);
    std::vector<pthread_t> c(3);
    for(int i = 0; i < p.size(); ++i)
    {
        pthread_create(&p[i], nullptr, Produce, (void*)bq);
    }
    for(int j = 0; j < c.size(); ++j)
    {
        pthread_create(&c[j], nullptr, Consumer, (void*)bq);
    }

    for(int i = 0; i < p.size(); ++i)
    {
        pthread_join(p[i], nullptr);
    }
    for(int j = 0; j < c.size(); ++j)
    {
        pthread_join(c[j], nullptr);
    }

    delete bq;
    return 0;
}
#endif

#if 0
// V1
bool Ready = false;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;       // 共享互斥锁
pthread_cond_t cond_producer = PTHREAD_COND_INITIALIZER; // 生产者条件变量
pthread_cond_t cond_consumer = PTHREAD_COND_INITIALIZER; // 消费者条件变量

void* Produce(void* args) {
    std::string name = static_cast<const char*>(args);
    while (true) {
        pthread_mutex_lock(&mutex);
        // 等待直到产品被消费（Ready == false）
        while (Ready == true) {
            pthread_cond_wait(&cond_producer, &mutex);
        }
        // 生产
        std::cout << name << ",开始生产..." << std::endl;
        Ready = true;
        // 通知消费者
        pthread_cond_signal(&cond_consumer);
        pthread_mutex_unlock(&mutex);
        sleep(1); // 模拟生产耗时
    }
    return nullptr;
}

void* Consumer(void* args) {
    std::string name = static_cast<const char*>(args);
    while (true) {
        pthread_mutex_lock(&mutex);
        // 等待直到产品就绪（Ready == true）
        while (Ready == false) {
            pthread_cond_wait(&cond_consumer, &mutex);
        }
        // 消费
        std::cout << name << ",开始消费..." << std::endl;
        Ready = false;
        // 通知生产者
        pthread_cond_signal(&cond_producer);
        pthread_mutex_unlock(&mutex);
    }
    return nullptr;
}


int main()
{
    // 单生产单消费
    pthread_t p; /* 生产者 */
    pthread_t c; /* 消费者 */
    
    pthread_create(&p, nullptr, Produce, (void*)"thread-p");
    pthread_create(&c, nullptr, Consumer, (void*)"thread-c");

    pthread_join(p, nullptr);
    pthread_join(c, nullptr);

    return 0;
}
#endif